package com.blog.security.handler;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;

import com.blog.security.exception.ServiceException;
import com.comon.core.constants.ExceptionConstants;
import com.comon.core.domain.result.R;
import com.comon.core.enums.ResultCode;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.Collection;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 请求方式不支持
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public R<?> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
                                                    HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
        return R.fail(ExceptionConstants.SERVER_DEFAULT_EXCEPTION);
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error(e.getMessage(), e);
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return R.fail(ResultCode.FAILED_PARAMS_VALIDATE.getCode(), message);
    }

    /**
     * 拦截未知的运行时异常，例如被除数不能为0
     */
    @ExceptionHandler(ServiceException.class)
    public R<?> handleServiceException(ServiceException e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        ResultCode resultCode = e.getResultCode();
        log.error("请求地址'{}',发生业务异常.{}", requestURI, resultCode.getMsg(),e);
        return R.fail(ExceptionConstants.SERVER_DEFAULT_EXCEPTION);
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public R<?> handleRuntimeException(RuntimeException e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生未知异常.", requestURI, e);
        return R.fail(ExceptionConstants.SERVER_DEFAULT_EXCEPTION);
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    public R<?> handleException(Exception e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生系统异常.", requestURI, e);
        return R.fail(ExceptionConstants.SERVER_DEFAULT_EXCEPTION);
    }

    @ExceptionHandler(BindException.class)
    public R<Void> handleBindException(BindException e) {
         log.error(e.getMessage());
         String message = join(e.getAllErrors(),
                 DefaultMessageSourceResolvable::getDefaultMessage,",");
         return R.fail(ResultCode.FAILED_PARAMS_VALIDATE.getCode(), message);
    }

    private <E> String join(Collection<E> collection, Function<E, String>
            function, CharSequence delimiter) {
         if (CollUtil.isEmpty(collection)) {
             return StrUtil.EMPTY;
             }
         return
                collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter));
    }

}
